import { Text, View } from '@tarojs/components';
import theme from '@/theme';
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import './index.scss';
import classNames from 'classnames';
import { Icon, PullView, ScrollView, Space, Button, Tag } from 'pd-taro-ui';
import { pxTransform } from '@tarojs/taro';
import Input from '../Input';
import { useReactive } from 'ahooks';
import SelectItem from './SelectItem';
import { transSelectedValueToValue, transValueToSelectedValue, useExpandKeys, useFilterOptions, useFlattenOptions } from './utils';
import { isEqual } from 'lodash';

type OptionItem = {
  label?: string;
  value?: any;
  /** 全禁用 */
  disabled?: boolean;
  /** 禁止选中 */
  disabledCheck?: boolean;
  /** 禁止展开 */
  disabledExpand?: boolean;
  children?: OptionItem[];
  [key: string]: any;
};
export interface SelectProps {
  placeholder?: string;
  value?: string | (string | number)[];
  onChange?: (value: SelectProps['value'], selectedItems: OptionItem[]) => void;
  onBlur?: any;
  staticed?: boolean;
  disabled?: boolean;
  compProps?: any;

  /** select下拉框, tree树框 */
  selectMode?: 'select' | 'tree';

  /** 渲染标签：默认label */
  labelField?: string;
  /** 渲染值：默认value */
  valueField?: string;
  /** 是否显示为一行，默认true, */
  inline?: boolean;
  /** 如果不设置value就不能选中 */
  options?: OptionItem[];
  onChangeOptions?: (options: OptionItem[]) => void;
  /** 是否显示清除按钮 */
  clearable?: boolean;
  /** 是否可搜索匹配 */
  searchable?: boolean;
  /** 是否多选 */
  multiple?: boolean;
  /** 是否拼接字符串，返回数组或字符串，默认true字符串 */
  joinValues?: boolean;
  /** 字符串拼接符号，默认, */
  delimiter?: string;

  /** 点击展开回调 */
  onExpand?: (item: OptionItem) => void;
  /** 异步查询接口，需要和onChangeOptions一起用。假如第一次加载无options，会自动执行一次 */
  deferApi?: (item?: OptionItem) => Promise<OptionItem[] | { data: OptionItem[]; [key: string]: any }>;
  /** 用于异步查询+只读页面时，无options时，自动匹配静态展示, 该列表不会展示到选择列表里 */
  extraOptions?: OptionItem[];
}

const Select = ({
  onChange,
  value,
  disabled,
  staticed,
  onBlur,
  placeholder = ' ',
  compProps,
  options = [],
  onChangeOptions,
  selectMode = 'select',
  labelField = 'label',
  valueField = 'value',
  clearable = false,
  searchable = false,
  multiple = false,
  joinValues = true,
  delimiter = ',',
  onExpand,
  deferApi,
  extraOptions = [],
}: SelectProps) => {
  const state = useReactive({
    show: false,
    selectedValue: [] as (string | number)[],
    searchStr: '',
  });
  const { expandKeys, toggleExpandItem, setExpandKeys } = useExpandKeys();
  const [loadingItemKey, setLoadingItemKey] = useState('');

  const flattenOptions = useFlattenOptions(options);

  const hadSelectedValue = !!state.selectedValue.length;

  const onToggleExpandItem = (key: string, item: any, isExpand: boolean) => {
    toggleExpandItem(key);
    if (isExpand) {
      if (deferApi && !item.children?.length) {
        onDeferApi(item);
      }
      onExpand?.(item);
    }
  };

  const toggleCheck = (item: OptionItem) => {
    if (disabled || item?.disabled || item?.disabledCheck) return;
    const isCheck = getIsCheck(item);
    const tempValue = item[valueField];
    if (typeof tempValue !== 'number' && typeof tempValue !== 'string') {
      console.log('Select.toggleCheck 非number和string 禁止选中', item);
      return;
    }
    if (!isCheck) {
      if (multiple) {
        state.selectedValue = state.selectedValue.concat(tempValue);
      } else {
        state.selectedValue = [tempValue];
      }
    } else {
      if (multiple) {
        state.selectedValue = state.selectedValue.filter(v => v !== tempValue);
      } else {
        state.selectedValue = [];
      }
    }
  };

  const getIsCheck = (item: any) => {
    return state.selectedValue.includes(item[valueField]);
  };

  const getIsLoading = useCallback(
    (item: any) => {
      return loadingItemKey === item[valueField];
    },
    [loadingItemKey, valueField],
  );

  const selectedItems = useMemo(() => {
    const list = flattenOptions.concat(extraOptions);
    return state.selectedValue.map(v => {
      return list.find(option => option[valueField] === v) || {};
    });
  }, [state.selectedValue, flattenOptions, valueField, extraOptions]);
  // console.log('render state.selectedValue', state.selectedValue, selectedItems, { multiple, hadSelectedValue });

  const staticStr = useMemo(() => {
    return selectedItems
      .map(item => {
        return item?.[labelField] || '';
      })
      .join(delimiter);
  }, [selectedItems, delimiter, labelField]);

  const open = () => {
    if (disabled) return;
    state.show = true;
  };
  const close = () => {
    state.show = false;
  };
  const submit = () => {
    onChange?.(transSelectedValueToValue(state.selectedValue, multiple, joinValues, delimiter), selectedItems);
    close();
  };
  const clear = () => {
    state.selectedValue = [];
    submit();
  };

  const onDeferApi = (item?: OptionItem) => {
    if (!deferApi || !onChangeOptions) return;
    if (item) setLoadingItemKey(item[valueField]);
    deferApi(item).then(data => {
      setLoadingItemKey('');
      let list: OptionItem[] = [];
      if (Array.isArray(data)) {
        list = data;
      } else if (Array.isArray(data?.data)) {
        list = data?.data;
      }
      if (item) {
        item.children = list;
        onChangeOptions(options.concat());
      } else {
        onChangeOptions(list);
      }
    });
  };

  const filterOptions = useFilterOptions(searchable, state.searchStr, options, flattenOptions, labelField);

  useEffect(() => {
    if (!state.show) {
      const selectedValue = transValueToSelectedValue(value, multiple, joinValues, delimiter);
      if (!isEqual(selectedValue, state.selectedValue.concat())) {
        state.selectedValue = selectedValue;
      }
    }
  }, [delimiter, joinValues, multiple, state, state.show, value]);

  useEffect(() => {
    if (!options?.length && deferApi && onChangeOptions) {
      onDeferApi();
    }
  }, []);

  if (staticed) {
    return <View className='pd-select--static'>{staticStr}</View>;
  }
  return (
    <>
      <View className={classNames({ 'pd-select': true, 'pd-select--disabled': disabled })}>
        <View className={classNames({ 'pd-select__content': true })} onClick={open}>
          {multiple && hadSelectedValue ? (
            <Space row wrap gap={8}>
              {selectedItems.map((item, index) => {
                return (
                  <Tag
                    key={index}
                    closable={!disabled}
                    onClose={e => {
                      e.stopPropagation?.();
                      toggleCheck(item);
                    }}>
                    {item?.[labelField]}
                  </Tag>
                );
              })}
            </Space>
          ) : (
            <Text className={classNames({ 'pd-select__text': true, 'pd-select__placeholder': !hadSelectedValue })}>
              {staticStr || placeholder || ' '}
            </Text>
          )}
        </View>
        {clearable && !disabled && hadSelectedValue && <Icon name='error' color='#bbb' size={36} onClick={clear} />}
        <Icon name='right' color='#bbb' size={36} />
      </View>

      <PullView open={state.show} onClose={close} side='bottom'>
        <View className='pd-select__modal'>
          <View className='pd-select__modal__header'>请选择</View>
          <View className='pd-select__modal__close' onClick={close}>
            <Icon name='close' size={46} />
          </View>
          {searchable && (
            <Input
              className='pd-select__modal__input'
              value={state.searchStr}
              onChange={v => (state.searchStr = v)}
              placeholder='搜索'
              clearable
            />
          )}
          <ScrollView>
            {filterOptions?.map((item, index) => {
              return (
                <SelectItem
                  selectMode={selectMode}
                  key={index}
                  getIsCheck={getIsCheck}
                  item={item}
                  labelField={labelField}
                  valueField={valueField}
                  expandKeys={expandKeys}
                  onToggleExpandItem={onToggleExpandItem}
                  toggleCheck={toggleCheck}
                  deepth={0}
                  disabled={item.disabled}
                  disabledExpand={item.disabledExpand}
                  disabledCheck={item.disabledCheck}
                  defer={!!deferApi}
                  getIsLoading={getIsLoading}></SelectItem>
              );
            })}
          </ScrollView>
          <Button type='primary' style={{ width: pxTransform(300), alignSelf: 'center', marginTop: pxTransform(30) }} onClick={submit}>
            确定
          </Button>
        </View>
      </PullView>
    </>
  );
};
export default Select;
